docker buildを速くするコツ
Dockerのイメージビルドを速くしたいkeroxp.icon 1行のコード変更で5秒くらいで終わらないと話にならない
遅くなる理由は主に以下の3つ
Dockerデーモンに送るtarファイルが大きい
dockerはビルド開始時にdocker daemonにDockerfileのディレクトリにあるファイルを全部tarして送る
なのでDockerfileのなかで../は参照できないのだ
これが大きいとtarするのに時間がかかる
.dockerignoreにファイルを書いておくと、これらはtarされずDockerデーモンに送られない
不要なファイルを除外しておくことが大事
細かいファイルを沢山除外するよりも、でかいディレクトリをまるごと除外していくほうが効果的
NOTE: ビルドコンテクストにファイルが送られないので、その後 ADDもCOPYもできなくなるので注意
軽くなりそうなリスト
.git
ランタイムで自身のgit情報を使っていない場合のみ
bundlerに怒られる場合はDockerfile内でRUN git initしておけばいい
node_modules
tmp, log, distなどホスト上で生成されたビルド関連ファイル
ここらへんはビルド時には無いことになってるので送っちゃダメ
パッケージのインストールが遅い
apk, yum, yarn, bundle, gemなど依存パッケージの インストールは毎回やり直すと当然遅い
これにはいろいろテクニックはあるのだけど銀の弾丸はない感
TIPS1: パッケージファイルのみのレイヤを作る
Dockerfile内でプロジェクトファイルをイメージ内にCOPYする際、以下のようにやると良くない(後述)
code: Dockerfile
COPY . /workspace
ADD, COPYコマンドは追加したすべてのファイルのチェックサムを計算して保存している
次回ビルド時、そのレイヤのチェックサムが同じならレイヤーキャッシュを使う
ここにあるように、RUNは直前までのすべてのレイヤ(正確には一つ前のRUNからそれまでのADD, COPY?)でキャッシュが使われていて、RUNの文字列が変わっていない場合はRUN自身もキャッシュを使う
一応イメージの中身が変わっていなければRUNの結果は冪等であるとする方針のようだ
それでいいと思う
apk --updateとかやっても、キャッシュが使われてたらupdateされない
そういう場合はdocker build --no-cacheを使う
なので、RUN yarn installやRUN bundle installをする直前まで、できるだけキャッシュをtaintしない
ここでDockerのmulti stage buildを使うといい
code: Dockerfile
FROM ruby:2.4.1-alpine AS gem-installer
WORKDIR /workspace
RUN bundle install --path vendor/bundle
FROM node:9.10-alpine AS yarn-installer
WORKDIR /workspace
RUN yarn install
FROM alpine
WORKDIR /workspace
RUN apk update --no-cache \
&& apk add bash curl nodejs \
&& ln -s "$HOME/.yarn/bin/yarn" /usr/local/bin/yarn
COPY --from=yarn-installer /workspace/node_modules /workspace/node_modules
COPY --from=gem-installer /workspace/vendor /workspace/vendor
COPY . /workspace
↑のようにyarn, bundlerのインストールだけを行うステージを作ると、package.json、Gemfileのどちらかだけが変更された場合でも、片方は再インストールにならない
code: Dockerfile
RUN bundle install && yarn install
のようにやると、Gemfile.lock, yarn.lockのどちらかが変更されただけでキャッシュが消えてbundle, yarn両方再インストールが走ってしまう
RUNを&&でまとめてレイヤーを最小限に抑えるというのがイメージ軽量化のテクニックだが、これはビルド効率とトレードオフになる
ビルドセマンティクスごとにレイヤーを分けてキャッシュをセマンティクスごとに使えるようにしたほうがいい
TIPS1とか言ってたけどこれが一番いい気がする
アプリケーションのビルドが遅い
これも↑と同様キャッシュを効かせられるかが鍵